package sii.predizioni;

import java.io.IOException;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.time.StopWatch;

import sii.commons.ConfigException;
import sii.commons.ConfigManager;
import sii.commons.Log;
import sii.commons.SimilarityItem;
import sii.commons.Utils;
import sii.dati.DataManagerException;
import sii.dati.DataManagerRatings;
import sii.dati.DataManagerSimilarita;


public class PredizioneSignificanceWeighting {
    float ust;
    float pst;
    int uswf;
    int pswf;
    float lambda;
    

    public PredizioneSignificanceWeighting() throws ConfigException  {
	ust = ConfigManager.getFloat("user_similarity_threshold");
	pst = ConfigManager.getFloat("profile_similarity_threshold");
	lambda = ConfigManager.getFloat("lambda");
	uswf = ConfigManager.getInt("user_significance_weighting_factor");
	pswf = ConfigManager.getInt("profile_significance_weighting_factor");

    }

   
    public int calcolaPredizione(int userId, int profileId)
	    throws DataManagerException, IOException, SQLException {
	StopWatch sw = new StopWatch();
	Log log = new Log(PredizioneSignificanceWeighting.class);
	sw.start();
	DataManagerSimilarita dms = DataManagerSimilarita.getInstance();
	DataManagerRatings dmr = DataManagerRatings.getInstance();

	float predizioneUtente ;
	float mediaUtente = dmr.getMedia();
	List<SimilarityItem> userSimilarList = dms.getSimilarUsers(userId,
		profileId);

	log.info("calcolo predizione iniziato...\t\t");
	float num = 0, den = 0;
	for (SimilarityItem si : userSimilarList) {
	    float simAdj = Math.min(uswf, si.commonRatingsSize) * si.Similarity;
	    if (simAdj > ust) {
		int ratingUtenteA;
		float mediaUtenteA;
		if (si.id1 == userId) {
		    mediaUtenteA = si.media2;
		    mediaUtente = si.media1;
		    ratingUtenteA = dmr.getRating(si.id2, profileId);
		} else {
		    mediaUtenteA = si.media1;
		    mediaUtente = si.media2;
		    ratingUtenteA = dmr.getRating(si.id1, profileId);
		}
		num += simAdj * (ratingUtenteA - mediaUtenteA);
		den += simAdj;
	    }

	}

	if (den != 0) {
	    predizioneUtente = num / den;
	} else {
	    predizioneUtente = mediaUtente;
	}
	sw.suspend();
	StopWatch sw2 = new StopWatch();
	log.info("predizione utente calcolata in    \t" + Utils.time(sw.getTime()));
	sw.resume();
	sw2.start();
	float predizioneProfilo;
	float mediaProfilo = dmr.getMedia();
	List<SimilarityItem> profileSimilarList = dms.getSimilarProfiles(
		profileId, userId);

	for (SimilarityItem si : profileSimilarList) {
	    float simAdj = Math.min(pswf, si.commonRatingsSize) * si.Similarity;
	    if (simAdj > pst) {
		int ratingProfiloA; 
		float mediaProfiloA;
		if (si.id1 == profileId) {
		    mediaProfiloA = si.media2;
		    mediaProfilo = si.media1;
		    ratingProfiloA= dmr.getRating(userId, si.id2);
		} else {
		    mediaProfiloA = si.media1;
		    mediaProfilo = si.media2;
		    ratingProfiloA= dmr.getRating(userId, si.id1);
		}
		num += simAdj * (ratingProfiloA - mediaProfiloA);
		den += simAdj;
	    }
	}

	if (den != 0) {
	    predizioneProfilo = num / den;
	} else {
	    predizioneProfilo = mediaProfilo;
	}
	sw.stop();
	sw2.stop();
	log.info("predizione profilo terminata in  \t" + Utils.time(sw2.getTime()));
	int predizione = Math.round(lambda*predizioneUtente + (1-lambda)*predizioneProfilo);
	log.info("predizione risultato: " + userId + "," + profileId + ","+predizione + ": \t" + Utils.time(sw.getTime()));
	
	return predizione;

    }
}
